<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>谷粒商城记录 | Kylin</title><meta name="keywords" content="记录"><meta name="author" content="Kylin"><meta name="copyright" content="Kylin"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="配置文件@RefreshScope实现配置自动更新  项目中的使用：每个微服务创建自己的命名空间，使用配置分组区分环境，dev、test、pro、   application.properties对应命名空间下，所属分组、应用名.properties。 图片表示application.properties。对应nacos中coupon命名空间，prod分组，Data Id名称为应用名gulimal">
<meta property="og:type" content="article">
<meta property="og:title" content="谷粒商城记录">
<meta property="og:url" content="https://www.codekylin.cn/40200.html">
<meta property="og:site_name" content="Kylin">
<meta property="og:description" content="配置文件@RefreshScope实现配置自动更新  项目中的使用：每个微服务创建自己的命名空间，使用配置分组区分环境，dev、test、pro、   application.properties对应命名空间下，所属分组、应用名.properties。 图片表示application.properties。对应nacos中coupon命名空间，prod分组，Data Id名称为应用名gulimal">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg">
<meta property="article:published_time" content="2022-01-04T08:19:03.000Z">
<meta property="article:modified_time" content="2022-07-12T11:47:29.800Z">
<meta property="article:author" content="Kylin">
<meta property="article:tag" content="记录">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg"><link rel="shortcut icon" href="https://qiniu.codekylin.cn/img/20200807181548.png"><link rel="canonical" href="https://www.codekylin.cn/40200"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//www.google-analytics.com" crossorigin=""/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//fonts.googleapis.com" crossorigin=""/><meta name="google-site-verification" content="gzeyWstt6NoTZKh7YFYNLNziL8HIZ8YH2Ug7xTDX5-Y"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?f76c34daefe747deee7c7be3ead2ba80";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-159334016-1"></script><script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-159334016-1');
</script><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
  noticeOutdate: {"limitDay":90,"position":"top","messagePrev":"自上次更新以来已经","messageNext":"天，文章的内容可能已过时或存在差异。"},
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: {"limitCount":50000,"languages":{"author":"作者: Kylin","link":"链接: ","source":"来源: Kylin","info":"著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"}},
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#FF0000","bgDark":"#2d3035","position":"bottom-left"},
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-07-12 19:47:29'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
          const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
          const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
          const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified

          if (t === undefined) {
            if (isLightMode) activateLightMode()
            else if (isDarkMode) activateDarkMode()
            else if (isNotSpecified || hasNoSupport) {
              const now = new Date()
              const hour = now.getHours()
              const isNight = hour <= 6 || hour >= 18
              isNight ? activateDarkMode() : activateLightMode()
            }
            window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
              if (saveToLocal.get('theme') === undefined) {
                e.matches ? activateDarkMode() : activateLightMode()
              }
            })
          } else if (t === 'light') activateLightMode()
          else activateDarkMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const fontSizeVal = saveToLocal.get('global-font-size')
    if (fontSizeVal !== undefined) {
      document.documentElement.style.setProperty('--global-font-size', fontSizeVal + 'px')
    }
    })(window)</script><link rel="stylesheet" href="https://qiniu.codekylin.cn/github/img/img/custom.css"><link rel="stylesheet" href="//at.alicdn.com/t/font_1993646_z05rabxf05h.css"><link rel="stylesheet" href="https://qiniu.codekylin.cn/github/img/img/icon.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="Kylin" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181526.jpg" onerror="onerror=null;src='https://qiniu.codekylin.cn/github/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">362</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">427</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/categories/"><div class="headline">分类</div><div class="length-num">101</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">Kylin</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">谷粒商城记录</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-01-04T08:19:03.000Z" title="发表于 2022-01-04 16:19:03">2022-01-04</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">6k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>26分钟</span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h3 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h3><p><code>@RefreshScope</code>实现配置自动更新</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/image-20210724115516250.png" alt="image-20210724115516250"></p>
<p>项目中的使用：每个微服务创建自己的命名空间，使用配置分组区分环境，dev、test、pro、</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/image-20210724115658170.png" alt="image-20210724115658170"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724122925501.png" alt="image-20210724122925501"></p>
<p><code>application.properties</code>对应命名空间下，所属分组、应用名.properties。</p>
<p>图片表示<code>application.properties</code>。对应nacos中<code>coupon</code>命名空间，<code>prod</code>分组，Data Id名称为应用名<code>gulimall-coupon.properties</code>文件。yml同理</p>
<h3 id="配置集"><a href="#配置集" class="headerlink" title="配置集"></a>配置集</h3><p>同时加载多个配置集</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/image-20210724120455633.png" alt="image-20210724120455633"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/image-20210724120746937.png" alt="image-20210724120746937"></p>
<p>注释配置文件</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/image-20210724121131511.png" alt="image-20210724121131511"></p>
<p>使用配置集</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724121556728.png" alt="image-20210724121556728"></p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#使用coupon命名空间</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.namespace</span>=<span class="string">29176167-82d9-46b0-9a00-687acca63fd4</span></span><br><span class="line"><span class="comment">##分组</span></span><br><span class="line"><span class="comment">#spring.cloud.nacos.config.group=prod</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#加载多个配置集</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[0].data-id</span>=<span class="string">datasource.yml</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[0].group</span>=<span class="string">dev</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[0].refresh</span>=<span class="string">true</span></span><br><span class="line"></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[1].data-id</span>=<span class="string">mybatis.yml</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[1].group</span>=<span class="string">dev</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[1].refresh</span>=<span class="string">true</span></span><br><span class="line"></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[2].data-id</span>=<span class="string">other.yml</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[2].group</span>=<span class="string">dev</span></span><br><span class="line"><span class="meta">spring.cloud.nacos.config.ext-config[2].refresh</span>=<span class="string">true</span></span><br></pre></td></tr></table></figure>

<p>此时访问<code>localhost:7000/coupon/coupon/test</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724121718295.png" alt="image-20210724121718295"></p>
<p>值是们项目中配置的值，并没有使用到相对应的配置文件</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724121834712.png" alt="image-20210724121834712"></p>
<p>这是因为</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724121903515.png" alt="image-20210724121903515"></p>
<p><code>No active profile set, falling back to default profiles: default</code> 我们没有设置使用配置文件的分组，默认使用的是<code>DEFAULT_GROUP</code>分组。当我们的配置集中没有程序中使用的配置则会使用默认分组的配置文件，但是coupon命名空间下没有这个默认分组的配置文件，则使用原程序的配置<code>application.properties</code></p>
<p>当取消注释设置使用<code>prod</code>分组后</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724122432983.png" alt="image-20210724122432983"></p>
<h3 id="Gatewa网关"><a href="#Gatewa网关" class="headerlink" title="Gatewa网关"></a>Gatewa网关</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724150407519.png" alt="image-20210724150407519"></p>
<p>引入<code>common</code>模块中引入了跟数据库有关的相关依赖，而网关项目又没配置数据库信息，从而启动报错，主启动程序排除解决报错。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724150644490.png" alt="image-20210724150644490"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//不需要使用数据库</span></span><br><span class="line"><span class="meta">@SpringBootApplication(exclude = &#123;DataSourceAutoConfiguration.class&#125;)</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GulimallGatewayApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(GulimallGatewayApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>前端发送请求到网关存在跨域问题</p>
<p><mark>协议名、域名、端口都要相同，其中一个不同都会产生跨越问题。</mark></p>
<p>网关统一解决跨域问题。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161302098.png" alt="image-20210724161302098"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161316459.png" alt="image-20210724161316459"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161342760.png" alt="image-20210724161342760"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161354136.png" alt="image-20210724161354136"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161026129.png" alt="image-20210724161026129"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GuliMallCorsConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CorsWebFilter <span class="title">corsWebFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        UrlBasedCorsConfigurationSource source = <span class="keyword">new</span> UrlBasedCorsConfigurationSource();</span><br><span class="line"></span><br><span class="line">        CorsConfiguration corsConfiguration = <span class="keyword">new</span> CorsConfiguration();</span><br><span class="line">        <span class="comment">//1.配置跨域</span></span><br><span class="line">        corsConfiguration.addAllowedHeader(<span class="string">&quot;*&quot;</span>);</span><br><span class="line">        corsConfiguration.addAllowedMethod(<span class="string">&quot;*&quot;</span>);</span><br><span class="line">        corsConfiguration.addAllowedOrigin(<span class="string">&quot;*&quot;</span>);</span><br><span class="line">        corsConfiguration.setAllowCredentials(<span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line">        source.registerCorsConfiguration(<span class="string">&quot;/**&quot;</span>, corsConfiguration);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> CorsWebFilter(source);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724161924283.png" alt="image-20210724161924283"></p>
<p>只希望有一个解决跨域，不希望有多个。将另一个注释，这里是<code>renren-fast</code>解决了。（网关解决跨域，人人就不要解决了，否则重复！没配网关的时候不会出现跨域问题，就是人人后台解决了）</p>
<h3 id="人人快速开发"><a href="#人人快速开发" class="headerlink" title="人人快速开发"></a>人人快速开发</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724153254658.png" alt="image-20210724153254658"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724153315999.png" alt="image-20210724153315999"></p>
<p><code>product/category</code>转换成路由为<code>product-category</code></p>
<p>根据规则页面则应该创建在<code>views</code>目录下<code>product</code>包下的<code>category.vue</code>文件中。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724154239421.png" alt="image-20210724154239421"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724160736662.png" alt="image-20210724160736662"></p>
<p>前端项目发送请求到网关中</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724160107864.png" alt="image-20210724160107864"></p>
<p>网关重写路径<code>RewritePath</code></p>
<p><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#global-filters">https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#global-filters</a></p>
<p><code>uri: lb://renren-fast</code>: lb负载均衡://应用名</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210729161213.png" alt="image-20210724163635845"></p>
<p>返回的数据Object中<code>data</code>属性中的<code>data</code>才是我们想要的。所用我们可以使用ES6的解构赋值语法。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724163808734.png" alt="image-20210724163808734"></p>
<p>只拿出返回数据的<code>data</code>属性值，<code>data.data</code>中则包含我们所要的数据。</p>
<h3 id="前端Vue"><a href="#前端Vue" class="headerlink" title="前端Vue"></a>前端Vue</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724173433318.png" alt="image-20210724173433318"></p>
<p>框中内容回显，应该使用请求查询当前数据库，得到数据再回显到页面上。避免当多人在页面上操作时一个人修改了，会导致当前数据滞后。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724181819622.png" alt="image-20210724181819622"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210724181843068.png" alt="image-20210724181843068"></p>
<p>以上图片ES6新语法。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725095649351.png" alt="image-20210725095649351"></p>
<h4 id="拖拽修改菜单功能"><a href="#拖拽修改菜单功能" class="headerlink" title="拖拽修改菜单功能"></a>拖拽修改菜单功能</h4><p><code>draggable</code>开启拖拽功能</p>
<p><code>allow-drop</code> 拖拽时判定目标节点能否被放置`Function(draggingNode, dropNode, type)``</p>
<p>``type` 参数有三种情况：’prev’、’inner’ 和 ‘next’，分别表示放置在目标节点前、插入至目标节点和放置在目标节点后</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725103418179.png" alt="image-20210725103418179"></p>
<p><code>node-drop</code> 拖拽成功完成时触发的事件。共四个参数，依次为：被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置（before、after、inner）、event</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725103827605.png" alt="image-20210725103827605"></p>
<h4 id="批量删除"><a href="#批量删除" class="headerlink" title="批量删除"></a>批量删除</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725153814273.png" alt="image-20210725153814273"></p>
<p>使用组件自带的方法<code>ref=&quot;xxx&quot;</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725153847537.png" alt="image-20210725153847537"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725153907961.png" alt="image-20210725153907961"></p>
<p><code>this.$refs.menuTree.getCheckedNodes();</code>调用树形组件的<strong>getCheckedNodes</strong>方法</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725154003981.png" alt="image-20210725154003981"></p>
<h2 id="OOS云存储"><a href="#OOS云存储" class="headerlink" title="OOS云存储"></a>OOS云存储</h2><p>阿里云OSS云存储首先创建一个<code>Bucket</code>。</p>
<h3 id="Bucket"><a href="#Bucket" class="headerlink" title="Bucket"></a>Bucket</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725211311976.png" alt="image-20210725211311976"></p>
<p><code>公共读</code>代表读不需要账户密码，写操作则需要。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725211518472.png" alt="image-20210725211518472"></p>
<p>可以点击上传文件进行上传操作，通过url访问。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725211842302.png" alt="image-20210725211842302"></p>
<h3 id="SDK"><a href="#SDK" class="headerlink" title="SDK"></a>SDK</h3><p><a target="_blank" rel="noopener" href="https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.923.4c6513c03fK1WG">https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.923.4c6513c03fK1WG</a></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725212228699.png" alt="image-20210725212228699"></p>
<p>首先安装SDK</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.aliyun.oss<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>aliyun-sdk-oss<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.10.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="上传文件"><a href="#上传文件" class="headerlink" title="上传文件"></a>上传文件</h3><p>简单上传文件</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725212529299.png" alt="image-20210725212529299"></p>
<p><code>Endpoint</code>地域节点，在Bucekt页面概览中可以找到。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725213041410.png" alt="image-20210725213041410"></p>
<p>在测试中将上面的代码进行测试。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725214419532.png" alt="image-20210725214419532"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1（杭州）为例，Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。</span></span><br><span class="line">String endpoint = <span class="string">&quot;yourEndpoint&quot;</span>;</span><br><span class="line"><span class="comment">// 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。</span></span><br><span class="line">String accessKeyId = <span class="string">&quot;yourAccessKeyId&quot;</span>;</span><br><span class="line">String accessKeySecret = <span class="string">&quot;yourAccessKeySecret&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建OSSClient实例。</span></span><br><span class="line">OSS ossClient = <span class="keyword">new</span> OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建PutObjectRequest对象。</span></span><br><span class="line"><span class="comment">// 依次填写Bucket名称（例如examplebucket）、Object完整路径（例如exampledir/exampleobject.txt）和本地文件的完整路径。Object完整路径中不能包含Bucket名称。</span></span><br><span class="line"><span class="comment">// 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。</span></span><br><span class="line">PutObjectRequest putObjectRequest = <span class="keyword">new</span> PutObjectRequest(<span class="string">&quot;examplebucket&quot;</span>, <span class="string">&quot;exampledir/exampleobject.txt&quot;</span>, <span class="keyword">new</span> File(<span class="string">&quot;D:\\localpath\\examplefile.txt&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。</span></span><br><span class="line"><span class="comment">// ObjectMetadata metadata = new ObjectMetadata();</span></span><br><span class="line"><span class="comment">// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());</span></span><br><span class="line"><span class="comment">// metadata.setObjectAcl(CannedAccessControlList.Private);</span></span><br><span class="line"><span class="comment">// putObjectRequest.setMetadata(metadata);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 上传文件。</span></span><br><span class="line">ossClient.putObject(putObjectRequest);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭OSSClient。</span></span><br><span class="line">ossClient.shutdown();            </span><br></pre></td></tr></table></figure>

<p>上传成功后，就能在我们给定的路径看到我们上传的文件。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725214536414.png" alt="image-20210725214536414"></p>
<h3 id="Alibaba-Cloud-OSS"><a href="#Alibaba-Cloud-OSS" class="headerlink" title="Alibaba Cloud OSS"></a>Alibaba Cloud OSS</h3><p><a target="_blank" rel="noopener" href="https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md">https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md</a></p>
<p><a target="_blank" rel="noopener" href="https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample">https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample</a></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725220653647.png" alt="image-20210725220653647"></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>aliyun-oss-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>将我们之前导入的SDK注释掉。这里要指定一下版本，可以区阿里云的Maven仓库查看依赖<a target="_blank" rel="noopener" href="https://maven.aliyun.com/mvn/search">https://maven.aliyun.com/mvn/search</a></p>
<h4 id="坑"><a href="#坑" class="headerlink" title="坑"></a>坑</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725222913248.png" alt="image-20210725222913248"></p>
<p>配置文件配置OSS</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#oss配置</span></span><br><span class="line"><span class="attr">alibaba:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">access-key:</span></span><br><span class="line">    <span class="attr">secret-key:</span></span><br><span class="line">    <span class="attr">oss:</span></span><br><span class="line">      <span class="attr">endpoint:</span></span><br></pre></td></tr></table></figure>

<h4 id="可行"><a href="#可行" class="headerlink" title="可行"></a>可行</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alicloud-oss<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">alicloud:</span></span><br><span class="line">      <span class="attr">access-key:</span> <span class="string">xxxxxxxxxxxxxx</span></span><br><span class="line">      <span class="attr">secret-key:</span> <span class="string">xxxxxxxxxxxxxxxxxxxxxx</span></span><br><span class="line">      <span class="attr">oss:</span></span><br><span class="line">        <span class="attr">endpoint:</span> <span class="string">oss-cn-shenzhen.aliyuncs.com</span></span><br></pre></td></tr></table></figure>

<p>我们可以通过<code>OSSClient</code>对象进行相关操作，省略了创建OSSClient的步骤。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210725223431409.png" alt="image-20210725223431409"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">GulimallProductApplicationTests</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired(required = false)</span></span><br><span class="line">    OSSClient ossClient;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testOSSUpload</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ossClient.putObject(<span class="string">&quot;mall-kylin&quot;</span>, <span class="string">&quot;exampledir/ossClient.txt&quot;</span>, <span class="keyword">new</span> File(<span class="string">&quot;C:\\Users\\kylin\\Desktop\\OSS.txt&quot;</span>));</span><br><span class="line">        <span class="comment">//关闭</span></span><br><span class="line">        ossClient.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>目前尚未知晓原因。</p>
<h4 id="服务端签名后直传"><a href="#服务端签名后直传" class="headerlink" title="服务端签名后直传"></a>服务端签名后直传</h4><p><a target="_blank" rel="noopener" href="https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1749.5a3c43d33sLRZe">https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1749.5a3c43d33sLRZe</a></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210726224157206.png" alt="image-20210726224157206"></p>
<p>选择代码示例Java。</p>
<p>应用服务器核心代码解析</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210726224417758.png" alt="image-20210726224417758"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span></span><br><span class="line"><span class="function">            <span class="keyword">throws</span> ServletException, IOException </span>&#123;</span><br><span class="line"></span><br><span class="line">        String accessId = <span class="string">&quot;&lt;yourAccessKeyId&gt;&quot;</span>; <span class="comment">// 请填写您的AccessKeyId。</span></span><br><span class="line">        String accessKey = <span class="string">&quot;&lt;yourAccessKeySecret&gt;&quot;</span>; <span class="comment">// 请填写您的AccessKeySecret。</span></span><br><span class="line">        String endpoint = <span class="string">&quot;oss-cn-hangzhou.aliyuncs.com&quot;</span>; <span class="comment">// 请填写您的 endpoint。</span></span><br><span class="line">        String bucket = <span class="string">&quot;bucket-name&quot;</span>; <span class="comment">// 请填写您的 bucketname 。</span></span><br><span class="line">        String host = <span class="string">&quot;https://&quot;</span> + bucket + <span class="string">&quot;.&quot;</span> + endpoint; <span class="comment">// host的格式为 bucketname.endpoint</span></span><br><span class="line">        <span class="comment">// callbackUrl为 上传回调服务器的URL，请将下面的IP和Port配置为您自己的真实信息。</span></span><br><span class="line">        String callbackUrl = <span class="string">&quot;http://88.88.88.88:8888&quot;</span>;</span><br><span class="line">        String dir = <span class="string">&quot;user-dir-prefix/&quot;</span>; <span class="comment">// 用户上传文件时指定的前缀。</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建OSSClient实例。</span></span><br><span class="line">        OSS ossClient = <span class="keyword">new</span> OSSClientBuilder().build(endpoint, accessId, accessKey);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">long</span> expireTime = <span class="number">30</span>;</span><br><span class="line">            <span class="keyword">long</span> expireEndTime = System.currentTimeMillis() + expireTime * <span class="number">1000</span>;</span><br><span class="line">            Date expiration = <span class="keyword">new</span> Date(expireEndTime);</span><br><span class="line">            <span class="comment">// PostObject请求最大可支持的文件大小为5 GB，即CONTENT_LENGTH_RANGE为5*1024*1024*1024。</span></span><br><span class="line">            PolicyConditions policyConds = <span class="keyword">new</span> PolicyConditions();</span><br><span class="line">            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, <span class="number">0</span>, <span class="number">1048576000</span>);</span><br><span class="line">            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);</span><br><span class="line"></span><br><span class="line">            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);</span><br><span class="line">            <span class="keyword">byte</span>[] binaryData = postPolicy.getBytes(<span class="string">&quot;utf-8&quot;</span>);</span><br><span class="line">            String encodedPolicy = BinaryUtil.toBase64String(binaryData);</span><br><span class="line">            String postSignature = ossClient.calculatePostSignature(postPolicy);</span><br><span class="line"></span><br><span class="line">            Map&lt;String, String&gt; respMap = <span class="keyword">new</span> LinkedHashMap&lt;String, String&gt;();</span><br><span class="line">            respMap.put(<span class="string">&quot;accessid&quot;</span>, accessId);</span><br><span class="line">            respMap.put(<span class="string">&quot;policy&quot;</span>, encodedPolicy);</span><br><span class="line">            respMap.put(<span class="string">&quot;signature&quot;</span>, postSignature);</span><br><span class="line">            respMap.put(<span class="string">&quot;dir&quot;</span>, dir);</span><br><span class="line">            respMap.put(<span class="string">&quot;host&quot;</span>, host);</span><br><span class="line">            respMap.put(<span class="string">&quot;expire&quot;</span>, String.valueOf(expireEndTime / <span class="number">1000</span>));</span><br><span class="line">            <span class="comment">// respMap.put(&quot;expire&quot;, formatISO8601Date(expiration));</span></span><br><span class="line"></span><br><span class="line">            JSONObject jasonCallback = <span class="keyword">new</span> JSONObject();</span><br><span class="line">            jasonCallback.put(<span class="string">&quot;callbackUrl&quot;</span>, callbackUrl);</span><br><span class="line">            jasonCallback.put(<span class="string">&quot;callbackBody&quot;</span>,</span><br><span class="line">                    <span class="string">&quot;filename=$&#123;object&#125;&amp;size=$&#123;size&#125;&amp;mimeType=$&#123;mimeType&#125;&amp;height=$&#123;imageInfo.height&#125;&amp;width=$&#123;imageInfo.width&#125;&quot;</span>);</span><br><span class="line">            jasonCallback.put(<span class="string">&quot;callbackBodyType&quot;</span>, <span class="string">&quot;application/x-www-form-urlencoded&quot;</span>);</span><br><span class="line">            String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());</span><br><span class="line">            respMap.put(<span class="string">&quot;callback&quot;</span>, base64CallbackBody);</span><br><span class="line"></span><br><span class="line">            JSONObject ja1 = JSONObject.fromObject(respMap);</span><br><span class="line">            <span class="comment">// System.out.println(ja1.toString());</span></span><br><span class="line">            response.setHeader(<span class="string">&quot;Access-Control-Allow-Origin&quot;</span>, <span class="string">&quot;*&quot;</span>);</span><br><span class="line">            response.setHeader(<span class="string">&quot;Access-Control-Allow-Methods&quot;</span>, <span class="string">&quot;GET, POST&quot;</span>);</span><br><span class="line">            response(request, response, ja1.toString());</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="comment">// Assert.fail(e.getMessage());</span></span><br><span class="line">            System.out.println(e.getMessage());</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123; </span><br><span class="line">            ossClient.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210726225017611.png" alt="image-20210726225017611"></p>
<p>这一段代码是返回Json解决跨域，跨域我们前面解决了。Json则使用的是<code>@RestController</code>也不用了。所以删掉这段代码直接返回respMap。</p>
<p>由于导入了<code>spring-cloud-starter-alicloud-oss</code>所以创建OssClient步骤可以省略，文件前缀按日期格式来划分。回调服务器的URL暂时用不到注释掉。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OssController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    OSSClient ossClient;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.cloud.alicloud.oss.endpoint&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String endpoint;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.cloud.alicloud.oss.bucket&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String bucket;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;spring.cloud.alicloud.access-key&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String accessId;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/oss/policy&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, String&gt; <span class="title">policy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        String host = <span class="string">&quot;https://&quot;</span> + bucket + <span class="string">&quot;.&quot;</span> + endpoint; <span class="comment">// host的格式为 bucketname.endpoint</span></span><br><span class="line">        <span class="comment">// callbackUrl为 上传回调服务器的URL，请将下面的IP和Port配置为您自己的真实信息。</span></span><br><span class="line">        <span class="comment">//String callbackUrl = &quot;http://88.88.88.88:8888&quot;;</span></span><br><span class="line">        String format = <span class="keyword">new</span> SimpleDateFormat(<span class="string">&quot;yyyy-MM-dd&quot;</span>).format(<span class="keyword">new</span> Date());</span><br><span class="line">        String dir = format + <span class="string">&quot;/&quot;</span>; <span class="comment">// 用户上传文件时指定的前缀。</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">long</span> expireTime = <span class="number">30</span>;</span><br><span class="line">            <span class="keyword">long</span> expireEndTime = System.currentTimeMillis() + expireTime * <span class="number">1000</span>;</span><br><span class="line">            Date expiration = <span class="keyword">new</span> Date(expireEndTime);</span><br><span class="line">            <span class="comment">// PostObject请求最大可支持的文件大小为5 GB，即CONTENT_LENGTH_RANGE为5*1024*1024*1024。</span></span><br><span class="line">            PolicyConditions policyConds = <span class="keyword">new</span> PolicyConditions();</span><br><span class="line">            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, <span class="number">0</span>, <span class="number">1048576000</span>);</span><br><span class="line">            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);</span><br><span class="line"></span><br><span class="line">            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);</span><br><span class="line">            <span class="keyword">byte</span>[] binaryData = postPolicy.getBytes(<span class="string">&quot;utf-8&quot;</span>);</span><br><span class="line">            String encodedPolicy = BinaryUtil.toBase64String(binaryData);</span><br><span class="line">            String postSignature = ossClient.calculatePostSignature(postPolicy);</span><br><span class="line"></span><br><span class="line">            Map&lt;String, String&gt; respMap = <span class="keyword">new</span> LinkedHashMap&lt;String, String&gt;();</span><br><span class="line">            respMap.put(<span class="string">&quot;accessid&quot;</span>, accessId);</span><br><span class="line">            respMap.put(<span class="string">&quot;policy&quot;</span>, encodedPolicy);</span><br><span class="line">            respMap.put(<span class="string">&quot;signature&quot;</span>, postSignature);</span><br><span class="line">            respMap.put(<span class="string">&quot;dir&quot;</span>, dir);</span><br><span class="line">            respMap.put(<span class="string">&quot;host&quot;</span>, host);</span><br><span class="line">            respMap.put(<span class="string">&quot;expire&quot;</span>, String.valueOf(expireEndTime / <span class="number">1000</span>));</span><br><span class="line">            <span class="comment">// respMap.put(&quot;expire&quot;, formatISO8601Date(expiration));</span></span><br><span class="line"></span><br><span class="line">            JSONObject jasonCallback = <span class="keyword">new</span> JSONObject();</span><br><span class="line">            <span class="comment">//jasonCallback.put(&quot;callbackUrl&quot;, callbackUrl);</span></span><br><span class="line">            jasonCallback.put(<span class="string">&quot;callbackBody&quot;</span>,</span><br><span class="line">                    <span class="string">&quot;filename=$&#123;object&#125;&amp;size=$&#123;size&#125;&amp;mimeType=$&#123;mimeType&#125;&amp;height=$&#123;imageInfo.height&#125;&amp;width=$&#123;imageInfo.width&#125;&quot;</span>);</span><br><span class="line">            jasonCallback.put(<span class="string">&quot;callbackBodyType&quot;</span>, <span class="string">&quot;application/x-www-form-urlencoded&quot;</span>);</span><br><span class="line">            String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());</span><br><span class="line">            respMap.put(<span class="string">&quot;callback&quot;</span>, base64CallbackBody);</span><br><span class="line">            <span class="keyword">return</span> respMap;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="comment">// Assert.fail(e.getMessage());</span></span><br><span class="line">            System.out.println(e.getMessage());</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            ossClient.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210726230653881.png" alt="image-20210726230653881"></p>
<p>同时配置网关</p>
<p><a target="_blank" rel="noopener" href="http://localhost:88/api/thirdparty/oss/policy">http://localhost:88/api/thirdparty/oss/policy</a></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="comment">#按顺序依次向下拦截</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">        <span class="comment">#http://localhost:88/?url=baidu</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">test_route</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">https://www.baidu.com</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Query=url,baidu</span></span><br><span class="line">        <span class="comment">#http://localhost:88/?url=qq</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">qq_route</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">https://www.qq.com</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Query=url,qq</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">product_route</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">lb://gulimall-product</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/api/product/**</span></span><br><span class="line">          <span class="attr">filters:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">RewritePath=/api/(?&lt;segment&gt;.*),/$\&#123;segment&#125;</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">third_party_route</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">lb://gulimall-third-party</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/api/thirdparty/**</span></span><br><span class="line">          <span class="attr">filters:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">RewritePath=/api/thirdparty/(?&lt;segment&gt;.*),/$\&#123;segment&#125;</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">admin_route</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">lb://renren-fast</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/api/**</span></span><br><span class="line">          <span class="attr">filters:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">RewritePath=/api/(?&lt;segment&gt;.*),/renren-fast/$\&#123;segment&#125;</span></span><br></pre></td></tr></table></figure>

<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210726231356438.png" alt="image-20210726231356438"></p>
<h4 id="前端Upload组件"><a href="#前端Upload组件" class="headerlink" title="前端Upload组件"></a>前端Upload组件</h4><p>拿到外网访问的Bucket域名</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727203950435.png" alt="image-20210727203950435"></p>
<p>修改成<code>action</code>的地址</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727204103136.png" alt="image-20210727204103136"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727205519052.png" alt="image-20210727205519052"></p>
<p>向阿里云OSS地发送请求的时候，出现了跨域问题。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727205702259.png" alt="image-20210727205702259"></p>
<p>配置跨域设置。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727205803900.png" alt="image-20210727205803900"></p>
<p>此时就解决了跨域问题。</p>
<p>表格自定义显示logo图片<a target="_blank" rel="noopener" href="https://element.eleme.io/#/zh-CN/component/table">https://element.eleme.io/#/zh-CN/component/table</a></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727211330246.png" alt="image-20210727211330246"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210727211508500.png" alt="image-20210727211508500"></p>
<h4 id="表单校验"><a href="#表单校验" class="headerlink" title="表单校验"></a>表单校验</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210728205357119.png" alt="image-20210728205357119"></p>
<p><a target="_blank" rel="noopener" href="https://element.eleme.io/#/zh-CN/component/form">https://element.eleme.io/#/zh-CN/component/form</a></p>
<p>Form 组件提供了表单验证的功能，只需要通过 <code>rules</code> 属性传入约定的验证规则，并将 Form-Item 的 <code>prop</code> 属性设置为需校验的字段名即可。校验规则参见 <a target="_blank" rel="noopener" href="https://github.com/yiminghe/async-validator">async-validator</a></p>
<h4 id="JSR303校验"><a href="#JSR303校验" class="headerlink" title="JSR303校验"></a>JSR303校验</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210728223819878.png" alt="image-20210728223819878"></p>
<p><code>javax.validation.constraints</code>包下注解进行校验。</p>
<p>控制器参数使用<code>@Valid</code>注解标注，迭代注解<code>@Validated</code>，获取校验结果<code>BindingResult</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210728224840707.png" alt="image-20210728224840707"></p>
<h4 id="统一异常处理"><a href="#统一异常处理" class="headerlink" title="统一异常处理"></a>统一异常处理</h4><p>使用<code>@ControllerAdvice</code>注解这是一个增强的 Controller。使用这个 Controller ，可以实现三个方面的功能：</p>
<ol>
<li>全局异常处理</li>
<li>全局数据绑定</li>
<li>全局数据预处理</li>
</ol>
<p><code>@ExceptionHandler</code>异常处理方法，处理指定的异常类型。</p>
<p><code>@RestControllerAdvice</code>=<code>@RequestBody</code>+<code>@ControllerAdvice</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210728232827128.png" alt="image-20210728232827128"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 统一异常处理</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> kylin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//@RequestBody</span></span><br><span class="line"><span class="comment">//@ControllerAdvice(basePackages = &quot;com.kylin.gulimall.product.controller&quot;)</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@RestControllerAdvice(basePackages = &quot;com.kylin.gulimall.product.controller&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MallExceptionControllerAdvice</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 处理JSR303校验抛出的异常</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(value = MethodArgumentNotValidException.class)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> R <span class="title">handlerValidException</span><span class="params">(MethodArgumentNotValidException e)</span> </span>&#123;</span><br><span class="line">        log.error(<span class="string">&quot;数据校验出现问题&#123;&#125;,异常类型&#123;&#125;&quot;</span>, e.getMessage(), e.getClass());</span><br><span class="line">        BindingResult bindingResult = e.getBindingResult();</span><br><span class="line">        Map&lt;String, String&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;(<span class="number">16</span>);</span><br><span class="line">        bindingResult.getFieldErrors().forEach(fieldError -&gt; &#123;</span><br><span class="line">            map.put(fieldError.getField(), fieldError.getDefaultMessage());</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg()).put(<span class="string">&quot;data&quot;</span>, map);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 处理所有异常</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(value = Throwable.class)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> R <span class="title">handleException</span><span class="params">(Throwable throwable)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMsg());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>定义错误代码枚举类</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210728232921327.png" alt="image-20210728232921327"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 错误码和错误信息定义类</span></span><br><span class="line"><span class="comment"> * 1. 错误码定义规则为5为数字</span></span><br><span class="line"><span class="comment"> * 2. 前两位表示业务场景，最后三位表示错误码。例如：100001。10:通用 001:系统未知异常</span></span><br><span class="line"><span class="comment"> * 3. 维护错误码后需要维护错误描述，将他们定义为枚举形式</span></span><br><span class="line"><span class="comment"> * 错误码列表：</span></span><br><span class="line"><span class="comment"> * 10: 通用</span></span><br><span class="line"><span class="comment"> * 001：参数格式校验</span></span><br><span class="line"><span class="comment"> * 002: 短信验证码频率太高</span></span><br><span class="line"><span class="comment"> * 11: 商品</span></span><br><span class="line"><span class="comment"> * 12: 订单</span></span><br><span class="line"><span class="comment"> * 13: 购物车</span></span><br><span class="line"><span class="comment"> * 14: 物流</span></span><br><span class="line"><span class="comment"> * 15: 用户</span></span><br><span class="line"><span class="comment"> * 21: 库存</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> kylin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">enum</span> <span class="title">BizCodeEnum</span> </span>&#123;</span><br><span class="line">    UNKNOWN_EXCEPTION(<span class="number">10000</span>, <span class="string">&quot;系统未知异常&quot;</span>),</span><br><span class="line"></span><br><span class="line">    VALID_EXCEPTION(<span class="number">10001</span>, <span class="string">&quot;参数格式校验失败&quot;</span>),</span><br><span class="line"></span><br><span class="line">    SMS_CODE_EXCEPTION(<span class="number">10002</span>, <span class="string">&quot;验证码获取频率太高,稍后再试&quot;</span>),</span><br><span class="line"></span><br><span class="line">    TO_MANY_REQUEST(<span class="number">10003</span>, <span class="string">&quot;请求流量过大&quot;</span>),</span><br><span class="line"></span><br><span class="line">    SMS_SEND_CODE_EXCEPTION(<span class="number">10403</span>, <span class="string">&quot;短信发送失败&quot;</span>),</span><br><span class="line"></span><br><span class="line">    USER_EXIST_EXCEPTION(<span class="number">15001</span>, <span class="string">&quot;用户已经存在&quot;</span>),</span><br><span class="line"></span><br><span class="line">    PHONE_EXIST_EXCEPTION(<span class="number">15002</span>, <span class="string">&quot;手机号已经存在&quot;</span>),</span><br><span class="line"></span><br><span class="line">    LOGINACTT_PASSWORD_ERROR(<span class="number">15003</span>, <span class="string">&quot;账号或密码错误&quot;</span>),</span><br><span class="line"></span><br><span class="line">    SOCIALUSER_LOGIN_ERROR(<span class="number">15004</span>, <span class="string">&quot;社交账号登录失败&quot;</span>),</span><br><span class="line"></span><br><span class="line">    NOT_STOCK_EXCEPTION(<span class="number">21000</span>, <span class="string">&quot;商品库存不足&quot;</span>),</span><br><span class="line"></span><br><span class="line">    PRODUCT_UP_EXCEPTION(<span class="number">11000</span>, <span class="string">&quot;商品上架异常&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> code;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String msg;</span><br><span class="line"></span><br><span class="line">    BizCodeEnum(<span class="keyword">int</span> code, String msg) &#123;</span><br><span class="line">        <span class="keyword">this</span>.code = code;</span><br><span class="line">        <span class="keyword">this</span>.msg = msg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getCode</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> code;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getMsg</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> msg;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="分组校验"><a href="#分组校验" class="headerlink" title="分组校验"></a>分组校验</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729141842300.png" alt="image-20210729141842300"></p>
<p>首先定义两个分组</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729141932693.png" alt="image-20210729141932693"></p>
<p>校验注解中的<code>group</code>属性指定所属分组</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729141956346.png" alt="image-20210729141956346"></p>
<p>参数中使用<code>@Validated</code>注解给value赋值，表明该参数所属分组。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729142110247.png" alt="image-20210729142110247"></p>
<p><code>group</code>属性没指定分组，个人感觉所属空分组。每个参数都指定不同分组的话，非常冗余。</p>
<h4 id="自定义校验注解"><a href="#自定义校验注解" class="headerlink" title="自定义校验注解"></a>自定义校验注解</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210729161154.png" alt="image-20210729160928985"></p>
<p>可以参考别人写好的注解</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729143629347.png" alt="image-20210729143629347"></p>
<p>直接将其复制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义校验注解</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> kylin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@Target(&#123;METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Constraint(validatedBy = &#123;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> ListValue &#123;</span><br><span class="line"></span><br><span class="line">    <span class="function">String <span class="title">message</span><span class="params">()</span> <span class="keyword">default</span> &quot;</span>&#123;com.kylin.common.valid.ListValue.message&#125;<span class="string">&quot;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Class&lt;?&gt;[] groups() default &#123;&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Class&lt;? extends Payload&gt;[] payload() default &#123;&#125;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    int[] value() default &#123;&#125;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>

<p>导入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>jakarta.validation<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jakarta.validation-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>自定义注解的默认message消息会从<code>ValidationMessages.properties</code>中读取message名称属性的值。也就是这里配置的<code>com.kylin.common.valid.ListValue.message</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729144725438.png" alt="image-20210729144725438"></p>
<p>接着编写自定义校验器实现<code>ConstraintValidator</code>接口</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/image-20210729151043772.png" alt="image-20210729151043772"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 自定义参数校验器</span><br><span class="line"> *</span><br><span class="line"> * @author kylin</span><br><span class="line"> */</span><br><span class="line">public class ListValueConstraintValidator implements ConstraintValidator&lt;ListValue, Integer&gt; &#123;</span><br><span class="line"></span><br><span class="line">    private Set&lt;Integer&gt; set = new HashSet&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 初始化方法</span><br><span class="line">     *</span><br><span class="line">     * @param constraintAnnotation 注解</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public void initialize(ListValue constraintAnnotation) &#123;</span><br><span class="line">        int[] value = constraintAnnotation.value();</span><br><span class="line">        for (int i : value) &#123;</span><br><span class="line">            set.add(i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 判断是否校验成功</span><br><span class="line">     *</span><br><span class="line">     * @param value   需要校验的值</span><br><span class="line">     * @param context</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public boolean isValid(Integer value, ConstraintValidatorContext context) &#123;</span><br><span class="line">        return set.contains(value);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在自定义校验注解中<code>@Constraint(validatedBy = &#123;&#125;)</code>指定校验器。<code>@Constraint(validatedBy = &#123;ListValueConstraintValidator.class&#125;)</code></p>
<h2 id="Elasticsearch"><a href="#Elasticsearch" class="headerlink" title="Elasticsearch"></a>Elasticsearch</h2><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>docker安装<code>elasticsearch</code></p>
<p><code>docker pull elasticsearch:7.4.2</code></p>
<ol>
<li>创建目录，挂载文件。授权</li>
<li>配置elasticsearch，允许所有的ip访问</li>
<li>docker允许命令 容器名为<code>elasticsearch</code> 开发9200、9300端口。当前以当节点允许，配置Java内存，-v挂载，-d运行images</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p /mydata/elasticsearch/config</span><br><span class="line">mkdir -p /mydata/elasticsearch/data</span><br><span class="line">chmod -R 777 /mydata/elasticsearch/</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;http.host: 0.0.0.0&quot;</span>&gt;&gt;/mydata/elasticsearch/config/elasticsearch.yml</span><br><span class="line"></span><br><span class="line">docker run --name elasticsearch -p 9200:9200 -p 9300:9300 --privileged=<span class="literal">true</span> \</span><br><span class="line">-e <span class="string">&quot;discovery.type=single-node&quot;</span> \</span><br><span class="line">-e ES_JAVA_OPTS=<span class="string">&quot;-Xms64m -Xmx128m&quot;</span> \</span><br><span class="line">-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \</span><br><span class="line">-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \</span><br><span class="line">-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \</span><br><span class="line">-d elasticsearch:7.4.2</span><br></pre></td></tr></table></figure>

<p><code>free -m</code>查看内存命令</p>
<p>docker安装<code>kibana</code></p>
<p><code>docker pull kibana:7.4.2</code></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 -d kibana:7.4.2</span><br></pre></td></tr></table></figure>

<h3 id="入门操作"><a href="#入门操作" class="headerlink" title="入门操作"></a>入门操作</h3><h4 id="新增"><a href="#新增" class="headerlink" title="新增"></a>新增</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806171403.png" alt="image-20210806171354295"></p>
<p>PUT和POST都可以</p>
<ol>
<li>POST新增。如果不指定id，会自动生成id。指定id就会修改这个数据，并新增版本号。</li>
<li>PUT可以新增可以修改。PUT必须指定id。由于PUT需要指定id，我们一般用来做修改操作，不指定id会报错。</li>
</ol>
<h4 id="查询文档"><a href="#查询文档" class="headerlink" title="查询文档"></a>查询文档</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806173047.png" alt="image-20210806173046325"></p>
<p><code>_seq_no</code>乐观锁<code>?if_seq_no=0&amp;if_primary_term=1</code></p>
<h4 id="更新文档"><a href="#更新文档" class="headerlink" title="更新文档"></a>更新文档</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806174605.png" alt="image-20210806174603841"></p>
<h4 id="删除文档或索引"><a href="#删除文档或索引" class="headerlink" title="删除文档或索引"></a>删除文档或索引</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806174909.png" alt="image-20210806174908113"></p>
<h4 id="批量API"><a href="#批量API" class="headerlink" title="批量API"></a>批量API</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806175100.png" alt="image-20210806175055903"></p>
<h3 id="进阶操作"><a href="#进阶操作" class="headerlink" title="进阶操作"></a>进阶操作</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806191138.png" alt="image-20210806191136797"></p>
<h4 id="检索信息"><a href="#检索信息" class="headerlink" title="检索信息"></a>检索信息</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806191236.png" alt="image-20210806191235375"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806191746.png" alt="image-20210806191741143"></p>
<h4 id="Query-DSL"><a href="#Query-DSL" class="headerlink" title="Query DSL"></a>Query DSL</h4><p><a target="_blank" rel="noopener" href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html</a></p>
<h3 id="IK分词器"><a href="#IK分词器" class="headerlink" title="IK分词器"></a>IK分词器</h3><h4 id="安装-1"><a href="#安装-1" class="headerlink" title="安装"></a>安装</h4><p>vagrant 使用<code>root</code>账号连接开启过程</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806193440.png" alt="image-20210806193439014"></p>
<p>安装<code>wget</code></p>
<p><code>yum install wget</code></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip</span><br><span class="line"></span><br><span class="line">unzip elasticsearch-analysis-ik-7.4.2.zip</span><br><span class="line"></span><br><span class="line">rm -rf *.zip</span><br><span class="line"></span><br><span class="line">mv ./* ik</span><br></pre></td></tr></table></figure>

<p>可以进入到容器里面</p>
<p><code>docker exec -it  elasticsearch /bin/bash</code></p>
<p>进入到了<code>cd /bin/</code></p>
<p>运行<code>elasticsearch-plugin list</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806200320.png" alt="image-20210806200318664"></p>
<p>安装成功。退出容器，重启<code>docker restart elasticserach</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806201226.png" alt="image-20210806201224934"></p>
<h4 id="词库"><a href="#词库" class="headerlink" title="词库"></a>词库</h4><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210806201513.png" alt="image-20210806201510643"></p>
<h3 id="可视化插件"><a href="#可视化插件" class="headerlink" title="可视化插件"></a>可视化插件</h3><p><a target="_blank" rel="noopener" href="https://blog.csdn.net/ljcgit/article/details/103856634">https://blog.csdn.net/ljcgit/article/details/103856634</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 显示文件</span></span><br><span class="line">ls</span><br><span class="line">结果如下：</span><br><span class="line">LICENSE.txt  README.textile  config  lib   modules</span><br><span class="line">NOTICE.txt   bin             data    logs  plugins</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 进入配置文件夹</span></span><br><span class="line"><span class="built_in">cd</span> config</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 显示文件</span></span><br><span class="line">ls</span><br><span class="line">结果如下：</span><br><span class="line">elasticsearch.keystore  ingest-geoip  log4j2.properties  roles.yml  users_roles</span><br><span class="line">elasticsearch.yml       jvm.options   role_mapping.yml   users</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 修改配置文件</span></span><br><span class="line">vi elasticsearch.yml</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 加入跨域配置</span></span><br><span class="line">http.cors.enabled: <span class="literal">true</span></span><br><span class="line">http.cors.allow-origin: <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>



<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker pull mobz/elasticsearch-head:5</span><br><span class="line"></span><br><span class="line">docker run -d --name es_admin -p 9100:9100 mobz/elasticsearch-head:5</span><br></pre></td></tr></table></figure>



<h2 id="Nginx"><a href="#Nginx" class="headerlink" title="Nginx"></a>Nginx</h2><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812104124.png" alt="image-20210812104116061"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812143955.png" alt="image-20210812143954097"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812144004.png" alt="image-20210812144004182"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812144030.png" alt="image-20210812144030106"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812144045.png" alt="image-20210812144044282"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812150059.png" alt="image-20210812150058383"></p>
<p><code>include /etc/nginx/conf.d/*.conf;</code></p>
<p><mark>这里会将这个目录下的配置文件一并包括生效，所以要注意这里配置文件所配置的信息。</mark></p>
<h3 id="负载均衡到网关"><a href="#负载均衡到网关" class="headerlink" title="负载均衡到网关"></a>负载均衡到网关</h3><p>首先配置本机的<code>host</code>输入gulimall.com访问虚拟机IP地址80端口</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812161759.png" alt="image-20210812161751339"></p>
<p>虚拟机的80端口运行了Nginx，docker中的<code>/etc/nginx/conf.d/gulimall.conf</code>中配置了<code>server_name gulimall.com</code>当访问的时候会携带host参数，代理地址为<code>http://gulimall</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812162227.png" alt="image-20210812162226922"></p>
<p>而Nginx的配置文件<code>nginx.conf</code>中配置了gulimall的负载均衡转发到了我们的网关。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812162447.png" alt="image-20210812162446209"></p>
<p>我们的网关则把请求转发到了我们的<code>gulimall-product</code>服务中。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812162557.png" alt="image-20210812162556180"></p>
<h2 id="JMeter"><a href="#JMeter" class="headerlink" title="JMeter"></a>JMeter</h2><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812193121.png" alt="image-20210812193120140"></p>
<h3 id="nginx测试"><a href="#nginx测试" class="headerlink" title="nginx测试"></a>nginx测试</h3><p>向<code>http://192.168.56.10/</code>发送测试</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812171705.png" alt="image-20210812171704547"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812171652.png" alt="image-20210812171651589"></p>
<p>使用<code>docker stats</code>实时查看容器运行情况</p>
<p>当我点击运行测试的时候，我们能看见</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812171817.png" alt="image-20210812171816759"></p>
<p>所以nginx是<code>CPU密集型</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812172127.png" alt="image-20210812172126327"></p>
<p>这里出现的异常是我们线程组给<code>stop</code>导致的，从而请求失败。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812172256.png" alt="image-20210812172255668"></p>
<ul>
<li>吞吐量/s：8086.8</li>
<li>90%响应时间：7</li>
<li>99%相应时间：18</li>
</ul>
<h3 id="网关测试"><a href="#网关测试" class="headerlink" title="网关测试"></a>网关测试</h3><p>向<code>http://localhost:88/</code>发送测试</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812192452.png" alt="image-20210812192450252"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812195028.png" alt="image-20210812195027308"></p>
<ul>
<li>吞吐量/s：26274.7</li>
<li>90%响应时间：3</li>
<li>99%相应时间：9</li>
</ul>
<h3 id="简单服务测试"><a href="#简单服务测试" class="headerlink" title="简单服务测试"></a>简单服务测试</h3><p>访问<code>http://localhost:10000/hello</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812194727.png" alt="image-20210812194718448"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812194740.png" alt="image-20210812194739087"></p>
<ul>
<li>吞吐量/s：45000</li>
<li>90%响应时间：2</li>
<li>99%相应时间：4</li>
</ul>
<h3 id="网关-简单服务测试"><a href="#网关-简单服务测试" class="headerlink" title="网关+简单服务测试"></a>网关+简单服务测试</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812194923.png" alt="image-20210812194923054"></p>
<p>访问测试<code>http://localhost:88/hello</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812195248.png" alt="image-20210812195247406"></p>
<ul>
<li>吞吐量/s：6409.0</li>
<li>90%响应时间：3</li>
<li>99%相应时间：13</li>
</ul>
<p>两个一加起来吞吐量大量减少。</p>
<h3 id="nginx-网关-简单服务测试"><a href="#nginx-网关-简单服务测试" class="headerlink" title="nginx+网关+简单服务测试"></a>nginx+网关+简单服务测试</h3><p>访问<code>http://gulimall.com/hello</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812195847.png" alt="image-20210812195846772"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812200014.png" alt="image-20210812200013128"></p>
<ul>
<li>吞吐量/s：2279.2</li>
<li>90%响应时间：34</li>
<li>99%相应时间：52</li>
</ul>
<p>中间件越多，性能损失越多，大多损失在网络交互了。</p>
<h3 id="首页一级菜单渲染"><a href="#首页一级菜单渲染" class="headerlink" title="首页一级菜单渲染"></a>首页一级菜单渲染</h3><p>访问测试<code>http://localhost:10000/</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812200643.png" alt="image-20210812200642108"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812200700.png" alt="image-20210812200700155"></p>
<ul>
<li><p>吞吐量/s：1831.5（db、thymeleaf）</p>
</li>
<li><p>90%响应时间：38</p>
</li>
<li><p>99%相应时间：61</p>
</li>
</ul>
<p><strong>tymeleaf开启缓存</strong></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812203213.png" alt="image-20210812203212229"></p>
<ul>
<li>吞吐量/s：2632.7</li>
<li>90%响应时间：27</li>
<li>99%相应时间：50</li>
</ul>
<p><strong>日志打印级别提高为erro</strong></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812204257.png" alt="image-20210812203618169"></p>
<ul>
<li>吞吐量/s：3125.5</li>
<li>90%响应时间：23</li>
<li>99%相应时间：42</li>
</ul>
<p><strong>字段设置为索引</strong></p>
<h3 id="首页三级分类数据获取"><a href="#首页三级分类数据获取" class="headerlink" title="首页三级分类数据获取"></a>首页三级分类数据获取</h3><p>访问测试<code>http://localhost:10000/index/catalog.json</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812201420.png" alt="image-20210812201419596"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812201433.png" alt="image-20210812201433004"></p>
<ul>
<li>吞吐量/s：323.2（db）</li>
<li>90%响应时间：176</li>
<li>99%相应时间：266</li>
</ul>
<h3 id="首页全量数据获取"><a href="#首页全量数据获取" class="headerlink" title="首页全量数据获取"></a>首页全量数据获取</h3><p>访问测试<code>http://localhost:10000/</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812202026.png" alt="image-20210812202025084"></p>
<p><code>高级</code>设置中勾选<code>从HTML文件获取所有内容的资源</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812202119.png" alt="image-20210812202119001"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812202309.png" alt="image-20210812202309018"></p>
<ul>
<li>吞吐量/s：62（静态资源）</li>
<li>90%响应时间：1122</li>
<li>99%相应时间：1510</li>
</ul>
<p>异常是因为有些文件报404</p>
<h3 id="Nginx动静分离优化"><a href="#Nginx动静分离优化" class="headerlink" title="Nginx动静分离优化"></a>Nginx动静分离优化</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812204223.png" alt="image-20210812204222971"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812205809.png" alt="image-20210812205808354"></p>
<p>将静态目录复制到虚拟机<code>/mydata/nginx/html/static</code>的目录下</p>
<p>进入docker容器，编写配置<code>/etc/nginx/conf.d/gulimall.conf</code>文件</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812210016.png" alt="image-20210812210015603"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">location /static/ &#123;	root /usr/share/nginx/html;&#125;</span><br></pre></td></tr></table></figure>

<p>其中容器内目录<code>/usr/share/nginx/html</code>目录挂载到了<code>/mydata/nginx/html/</code>也就是我们存放静态资源的地方。</p>
<p>访问<code>http://gulimall.com</code>进行测试</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210812210556.png" alt="image-20210812210555606"></p>
<h2 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h2><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813090918.png" alt="image-20210813090910495"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813091003.png" alt="image-20210813091002888"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813090934.png" alt="image-20210813090933599"></p>
<h3 id="redis"><a href="#redis" class="headerlink" title="redis"></a>redis</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813091750.png" alt="image-20210813091749522"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StringRedisTemplate</span> <span class="keyword">extends</span> <span class="title">RedisTemplate</span>&lt;<span class="title">String</span>, <span class="title">String</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Constructs a new &lt;code&gt;StringRedisTemplate&lt;/code&gt; instance. &#123;<span class="doctag">@link</span> #setConnectionFactory(RedisConnectionFactory)&#125;</span></span><br><span class="line"><span class="comment">	 * and &#123;<span class="doctag">@link</span> #afterPropertiesSet()&#125; still need to be called.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">StringRedisTemplate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		setKeySerializer(RedisSerializer.string());</span><br><span class="line">		setValueSerializer(RedisSerializer.string());</span><br><span class="line">		setHashKeySerializer(RedisSerializer.string());</span><br><span class="line">		setHashValueSerializer(RedisSerializer.string());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Constructs a new &lt;code&gt;StringRedisTemplate&lt;/code&gt; instance ready to be used.</span></span><br><span class="line"><span class="comment">	 *</span></span><br><span class="line"><span class="comment">	 * <span class="doctag">@param</span> connectionFactory connection factory for creating new connections</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">StringRedisTemplate</span><span class="params">(RedisConnectionFactory connectionFactory)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>();</span><br><span class="line">		setConnectionFactory(connectionFactory);</span><br><span class="line">		afterPropertiesSet();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> RedisConnection <span class="title">preProcessConnection</span><span class="params">(RedisConnection connection, <span class="keyword">boolean</span> existingConnection)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> DefaultStringRedisConnection(connection);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>StringRedisTemplate</code>是专门操作<code>string</code>类型数据。 </p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813093157.png" alt="image-20210813093156229"></p>
<p>使用redis将数据存入到缓存中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> Map&lt;String, List&lt;Catelog2Vo&gt;&gt; getCatelogJson() &#123;</span><br><span class="line">    <span class="comment">//1.加入缓存逻辑，缓存中存的数据就是json字符串</span></span><br><span class="line">    String catalogJson = redisTemplate.opsForValue().get(<span class="string">&quot;catalogJson&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (StringUtils.isEmpty(catalogJson)) &#123;</span><br><span class="line">        <span class="comment">//2.缓存中没有，查询数据库</span></span><br><span class="line">        Map&lt;String, List&lt;Catelog2Vo&gt;&gt; catalogJsonFromDB = getCatalogJsonFromDB();</span><br><span class="line">        <span class="comment">//3.查询到的数据再放入缓存，将对象转为json放在缓存中</span></span><br><span class="line">        String s = JSON.toJSONString(catalogJsonFromDB);</span><br><span class="line">        redisTemplate.opsForValue().set(<span class="string">&quot;catalogJson&quot;</span>, s);</span><br><span class="line">        <span class="keyword">return</span> catalogJsonFromDB;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//Json字符串--&gt;对象</span></span><br><span class="line">    Map&lt;String, List&lt;Catelog2Vo&gt;&gt; result = JSON.parseObject(catalogJson, <span class="keyword">new</span> TypeReference&lt;Map&lt;String, List&lt;Catelog2Vo&gt;&gt;&gt;() &#123;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>此时压测访问首页三级分类数据获取<code>http://localhost:10000/index/catalog.json</code>（日志关闭，thymeleaf缓存开启，索引创建）</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813094113.png" alt="image-20210813094112302"></p>
<ul>
<li>吞吐量/s：1351</li>
<li>90%响应时间：44</li>
<li>99%相应时间：99</li>
</ul>
<p>出现堆外内存溢出：<code>OutOfDirectMemoryError</code>（lettuce5.2.1暂时没出现，5.1.8出现问题）</p>
<ul>
<li>springboot2.0以后默认使用lettuce作为操作redis的客户端。它使用netty进行网络通信。</li>
<li>lettuce的bug导致netty堆外内存溢出</li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813104440.png" alt="image-20210813101516117"></p>
<h3 id="缓存穿透"><a href="#缓存穿透" class="headerlink" title="缓存穿透"></a>缓存穿透</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813104415.png" alt="image-20210813104402637"></p>
<h3 id="缓存雪崩"><a href="#缓存雪崩" class="headerlink" title="缓存雪崩"></a>缓存雪崩</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813104424.png" alt="image-20210813104423528"></p>
<h3 id="缓存击穿"><a href="#缓存击穿" class="headerlink" title="缓存击穿"></a>缓存击穿</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813104511.png" alt="image-20210813104510337"></p>
<h3 id="分布式锁"><a href="#分布式锁" class="headerlink" title="分布式锁"></a>分布式锁</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813111420.png" alt="image-20210813111419751"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813114338.png" alt="image-20210813114326039"></p>
<p><strong>结果放入缓存这步操作应该放在锁内，否则会因为网络通信延迟导致又查询了一次数据库。</strong></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813143734.png" alt="image-20210813143732232"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813143752.png" alt="image-20210813143747795"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813145121.png" alt="image-20210813145120148"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813145512.png" alt="image-20210813145511448"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813145540.png" alt="image-20210813145538707"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813145603.png" alt="image-20210813145602560"></p>
<h4 id="Redisson"><a href="#Redisson" class="headerlink" title="Redisson"></a>Redisson</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://github.com/redisson/redisson/wiki/Table-of-Content">https://github.com/redisson/redisson/wiki/Table-of-Content</a></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 所有对Redisson的使用都是通过RedissonClient对象</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Bean(destroyMethod = &quot;shutdown&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> RedissonClient <span class="title">redisson</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//1.创建配置</span></span><br><span class="line">    Config config = <span class="keyword">new</span> Config();</span><br><span class="line">    config.useSingleServer().setAddress(<span class="string">&quot;redis://192.168.56.10:6379&quot;</span>);</span><br><span class="line">    <span class="comment">//2.根据Config创建出RedissonClient示例</span></span><br><span class="line">    RedissonClient redissonClient = Redisson.create(config);</span><br><span class="line">    <span class="keyword">return</span> redissonClient;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="缓存数据一致性"><a href="#缓存数据一致性" class="headerlink" title="缓存数据一致性"></a>缓存数据一致性</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813194302.png" alt="image-20210813194300518"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813194312.png" alt="image-20210813194310763"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813194329.png" alt="image-20210813194328400"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813194345.png" alt="image-20210813194344403"></p>
<h3 id="SpringCache"><a href="#SpringCache" class="headerlink" title="SpringCache"></a>SpringCache</h3><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210813195754.png" alt="image-20210813195753380"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210814102653.png" alt="image-20210814102652593"></p>
<p>引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-cache<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210814101006.png" alt="image-20210814101005106"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Cacheable(value = &#123;&quot;category&quot;&#125;, key = &quot;#root.method.name&quot;, sync = true)</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> List&lt;CategoryEntity&gt; <span class="title">getLevel1Categories</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;get Level 1 Categories........&quot;</span>);</span><br><span class="line">    <span class="keyword">long</span> l = System.currentTimeMillis();</span><br><span class="line">    List&lt;CategoryEntity&gt; categoryEntities = <span class="keyword">this</span>.baseMapper.selectList(</span><br><span class="line">            <span class="keyword">new</span> QueryWrapper&lt;CategoryEntity&gt;().eq(<span class="string">&quot;parent_cid&quot;</span>, <span class="number">0</span>));</span><br><span class="line">    System.out.println(<span class="string">&quot;消耗时间：&quot;</span> + (System.currentTimeMillis() - l));</span><br><span class="line">    <span class="keyword">return</span> categoryEntities;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20210814110713.png" alt="image-20210814110712397"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableConfigurationProperties(CacheProperties.class)</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableCaching</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyCacheConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 配置文件的配置没有用上</span></span><br><span class="line"><span class="comment">     * 1. 原来和配置文件绑定的配置类为：<span class="doctag">@ConfigurationProperties</span>(prefix = &quot;spring.cache&quot;)</span></span><br><span class="line"><span class="comment">     *                                public class CacheProperties</span></span><br><span class="line"><span class="comment">     * &lt;p&gt;</span></span><br><span class="line"><span class="comment">     * 2. 要让他生效，要加上 <span class="doctag">@EnableConfigurationProperties</span>(CacheProperties.class)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RedisCacheConfiguration <span class="title">redisCacheConfiguration</span><span class="params">(CacheProperties cacheProperties)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//序列化</span></span><br><span class="line">        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(<span class="keyword">new</span> StringRedisSerializer()));</span><br><span class="line">        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(<span class="keyword">new</span> GenericJackson2JsonRedisSerializer()));</span><br><span class="line"></span><br><span class="line">        CacheProperties.Redis redisProperties = cacheProperties.getRedis();</span><br><span class="line">        <span class="comment">//将配置文件中所有的配置都生效</span></span><br><span class="line">        <span class="keyword">if</span> (redisProperties.getTimeToLive() != <span class="keyword">null</span>) &#123;</span><br><span class="line">            config = config.entryTtl(redisProperties.getTimeToLive());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (redisProperties.getKeyPrefix() != <span class="keyword">null</span>) &#123;</span><br><span class="line">            config = config.prefixKeysWith(redisProperties.getKeyPrefix());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!redisProperties.isCacheNullValues()) &#123;</span><br><span class="line">            config = config.disableCachingNullValues();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!redisProperties.isUseKeyPrefix()) &#123;</span><br><span class="line">            config = config.disableKeyPrefix();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> config;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>相关配置文件</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">spring.cache.type</span>=<span class="string">redis</span></span><br><span class="line"><span class="comment">#毫秒</span></span><br><span class="line"><span class="meta">spring.cache.redis.time-to-live</span>=<span class="string">3600000</span></span><br><span class="line"><span class="comment">#如果指定了前缀就用我们指定的前缀，如果没有就默认使用缓存的名字作为前缀</span></span><br><span class="line"><span class="meta">spring.cache.redis.key-prefix</span>=<span class="string">CACHE_</span></span><br><span class="line"><span class="comment">#是否使用key前缀</span></span><br><span class="line"><span class="meta">spring.cache.redis.use-key-prefix</span>=<span class="string">true</span></span><br><span class="line"><span class="comment">#是否缓存空值，防止缓存穿透</span></span><br><span class="line"><span class="meta">spring.cache.redis.cache-null-values</span>=<span class="string">true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="异步"><a href="#异步" class="headerlink" title="异步"></a>异步</h2><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210817144353440.png" alt="image-20210817144353440"></p>
<h3 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h3><p><a target="_blank" rel="noopener" href="https://codekylin.cn/1019.html">JUC之线程池 | Kylin (codekylin.cn)</a></p>
<h3 id="CompletableFuture"><a href="#CompletableFuture" class="headerlink" title="CompletableFuture"></a>CompletableFuture</h3><p><code>CompletableFuture</code>类似前端的<code>promise</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818092304976.png" alt="image-20210818092304976"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818094039521.png" alt="image-20210818094039521"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818094728948.png" alt="image-20210818094728948"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818095834087.png" alt="image-20210818095834087"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818111217185.png" alt="image-20210818111217185"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818152255093.png" alt="image-20210818152255093"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818153559996.png" alt="image-20210818153559996"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/github/img/imgimage-20210818153618868.png" alt="image-20210818153618868"></p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">Kylin</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://www.codekylin.cn/40200.html">https://www.codekylin.cn/40200.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://www.codekylin.cn" target="_blank">Kylin</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E8%AE%B0%E5%BD%95/">记录</a></div><div class="post_share"><div class="social-share" data-image="https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button button--animated"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="https://qiniu.codekylin.cn/img/20200807181442.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181442.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="https://qiniu.codekylin.cn/img/20200807181505.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181505.jpg" alt="支付寶"/></a><div class="post-qr-code-desc">支付寶</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/7569.html"><img class="prev-cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-76qvyy.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Docker常用命令</div></div></a></div><div class="next-post pull-right"><a href="/64631.html"><img class="next-cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-5wqmj8.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Redis分布式锁</div></div></a></div></nav><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181526.jpg" onerror="this.onerror=null;this.src='https://qiniu.codekylin.cn/github/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">Kylin</div><div class="author-info__description">学习不易，努力努力~</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">362</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">427</div></a></div><div class="card-info-data-item is-center"><a href="/categories/"><div class="headline">分类</div><div class="length-num">101</div></a></div></div><a class="button--animated" id="card-info-btn"><i class="fas fa-bookmark"></i><span>加入书签</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/kylincw" target="_blank" title="Github"><i class="iconfont icon-github"></i></a><a class="social-icon" href="tencent://message/?Menu=yes&amp;uin=171346168&amp;Service=300&amp;sigT=45a1e5847943b64c6ff3990f8a9e644d2b31356cb0b4ac6b24663a3c8dd0f8aa12a595b1714f9d45" target="_blank" title="qq"><i class="iconfont icon-qq"></i></a><a class="social-icon" href="https://space.bilibili.com/53836035" target="_blank" title="BiliBili"><i class="iconfont icon-bilibili-line"></i></a><a class="social-icon" href="mailto:zhang171346168@qq.com" target="_blank" title="Email"><i class="iconfont icon-email1"></i></a><a class="social-icon" href="/atom.xml" target="_blank" title="RSS"><i class="iconfont icon-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">学习不易，努力努力！</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-number">1.</span> <span class="toc-text">配置文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E9%9B%86"><span class="toc-number">2.</span> <span class="toc-text">配置集</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Gatewa%E7%BD%91%E5%85%B3"><span class="toc-number">3.</span> <span class="toc-text">Gatewa网关</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BA%BA%E4%BA%BA%E5%BF%AB%E9%80%9F%E5%BC%80%E5%8F%91"><span class="toc-number">4.</span> <span class="toc-text">人人快速开发</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%89%8D%E7%AB%AFVue"><span class="toc-number">5.</span> <span class="toc-text">前端Vue</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8B%96%E6%8B%BD%E4%BF%AE%E6%94%B9%E8%8F%9C%E5%8D%95%E5%8A%9F%E8%83%BD"><span class="toc-number">5.1.</span> <span class="toc-text">拖拽修改菜单功能</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4"><span class="toc-number">5.2.</span> <span class="toc-text">批量删除</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#OOS%E4%BA%91%E5%AD%98%E5%82%A8"><span class="toc-number"></span> <span class="toc-text">OOS云存储</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Bucket"><span class="toc-number">1.</span> <span class="toc-text">Bucket</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SDK"><span class="toc-number">2.</span> <span class="toc-text">SDK</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6"><span class="toc-number">3.</span> <span class="toc-text">上传文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Alibaba-Cloud-OSS"><span class="toc-number">4.</span> <span class="toc-text">Alibaba Cloud OSS</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9D%91"><span class="toc-number">4.1.</span> <span class="toc-text">坑</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8F%AF%E8%A1%8C"><span class="toc-number">4.2.</span> <span class="toc-text">可行</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%AD%BE%E5%90%8D%E5%90%8E%E7%9B%B4%E4%BC%A0"><span class="toc-number">4.3.</span> <span class="toc-text">服务端签名后直传</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%89%8D%E7%AB%AFUpload%E7%BB%84%E4%BB%B6"><span class="toc-number">4.4.</span> <span class="toc-text">前端Upload组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A1%A8%E5%8D%95%E6%A0%A1%E9%AA%8C"><span class="toc-number">4.5.</span> <span class="toc-text">表单校验</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#JSR303%E6%A0%A1%E9%AA%8C"><span class="toc-number">4.6.</span> <span class="toc-text">JSR303校验</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%9F%E4%B8%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86"><span class="toc-number">4.7.</span> <span class="toc-text">统一异常处理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%86%E7%BB%84%E6%A0%A1%E9%AA%8C"><span class="toc-number">4.8.</span> <span class="toc-text">分组校验</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3"><span class="toc-number">4.9.</span> <span class="toc-text">自定义校验注解</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Elasticsearch"><span class="toc-number"></span> <span class="toc-text">Elasticsearch</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%89%E8%A3%85"><span class="toc-number">1.</span> <span class="toc-text">安装</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%A5%E9%97%A8%E6%93%8D%E4%BD%9C"><span class="toc-number">2.</span> <span class="toc-text">入门操作</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%96%B0%E5%A2%9E"><span class="toc-number">2.1.</span> <span class="toc-text">新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9F%A5%E8%AF%A2%E6%96%87%E6%A1%A3"><span class="toc-number">2.2.</span> <span class="toc-text">查询文档</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9B%B4%E6%96%B0%E6%96%87%E6%A1%A3"><span class="toc-number">2.3.</span> <span class="toc-text">更新文档</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A0%E9%99%A4%E6%96%87%E6%A1%A3%E6%88%96%E7%B4%A2%E5%BC%95"><span class="toc-number">2.4.</span> <span class="toc-text">删除文档或索引</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%89%B9%E9%87%8FAPI"><span class="toc-number">2.5.</span> <span class="toc-text">批量API</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%9B%E9%98%B6%E6%93%8D%E4%BD%9C"><span class="toc-number">3.</span> <span class="toc-text">进阶操作</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A3%80%E7%B4%A2%E4%BF%A1%E6%81%AF"><span class="toc-number">3.1.</span> <span class="toc-text">检索信息</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Query-DSL"><span class="toc-number">3.2.</span> <span class="toc-text">Query DSL</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#IK%E5%88%86%E8%AF%8D%E5%99%A8"><span class="toc-number">4.</span> <span class="toc-text">IK分词器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%89%E8%A3%85-1"><span class="toc-number">4.1.</span> <span class="toc-text">安装</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AF%8D%E5%BA%93"><span class="toc-number">4.2.</span> <span class="toc-text">词库</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%AF%E8%A7%86%E5%8C%96%E6%8F%92%E4%BB%B6"><span class="toc-number">5.</span> <span class="toc-text">可视化插件</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Nginx"><span class="toc-number"></span> <span class="toc-text">Nginx</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%88%B0%E7%BD%91%E5%85%B3"><span class="toc-number">1.</span> <span class="toc-text">负载均衡到网关</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JMeter"><span class="toc-number"></span> <span class="toc-text">JMeter</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#nginx%E6%B5%8B%E8%AF%95"><span class="toc-number">1.</span> <span class="toc-text">nginx测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BD%91%E5%85%B3%E6%B5%8B%E8%AF%95"><span class="toc-number">2.</span> <span class="toc-text">网关测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AE%80%E5%8D%95%E6%9C%8D%E5%8A%A1%E6%B5%8B%E8%AF%95"><span class="toc-number">3.</span> <span class="toc-text">简单服务测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BD%91%E5%85%B3-%E7%AE%80%E5%8D%95%E6%9C%8D%E5%8A%A1%E6%B5%8B%E8%AF%95"><span class="toc-number">4.</span> <span class="toc-text">网关+简单服务测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#nginx-%E7%BD%91%E5%85%B3-%E7%AE%80%E5%8D%95%E6%9C%8D%E5%8A%A1%E6%B5%8B%E8%AF%95"><span class="toc-number">5.</span> <span class="toc-text">nginx+网关+简单服务测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A6%96%E9%A1%B5%E4%B8%80%E7%BA%A7%E8%8F%9C%E5%8D%95%E6%B8%B2%E6%9F%93"><span class="toc-number">6.</span> <span class="toc-text">首页一级菜单渲染</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A6%96%E9%A1%B5%E4%B8%89%E7%BA%A7%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96"><span class="toc-number">7.</span> <span class="toc-text">首页三级分类数据获取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A6%96%E9%A1%B5%E5%85%A8%E9%87%8F%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96"><span class="toc-number">8.</span> <span class="toc-text">首页全量数据获取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Nginx%E5%8A%A8%E9%9D%99%E5%88%86%E7%A6%BB%E4%BC%98%E5%8C%96"><span class="toc-number">9.</span> <span class="toc-text">Nginx动静分离优化</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BC%93%E5%AD%98"><span class="toc-number"></span> <span class="toc-text">缓存</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#redis"><span class="toc-number">1.</span> <span class="toc-text">redis</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F"><span class="toc-number">2.</span> <span class="toc-text">缓存穿透</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9"><span class="toc-number">3.</span> <span class="toc-text">缓存雪崩</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF"><span class="toc-number">4.</span> <span class="toc-text">缓存击穿</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81"><span class="toc-number">5.</span> <span class="toc-text">分布式锁</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Redisson"><span class="toc-number">5.1.</span> <span class="toc-text">Redisson</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E6%80%A7"><span class="toc-number">6.</span> <span class="toc-text">缓存数据一致性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringCache"><span class="toc-number">7.</span> <span class="toc-text">SpringCache</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BC%82%E6%AD%A5"><span class="toc-number"></span> <span class="toc-text">异步</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="toc-number">1.</span> <span class="toc-text">线程池</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#CompletableFuture"><span class="toc-number">2.</span> <span class="toc-text">CompletableFuture</span></a></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/56352.html" title="be动词"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/博客封面10.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="be动词"/></a><div class="content"><a class="title" href="/56352.html" title="be动词">be动词</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/36436.html" title="JVM堆内存"><img data-lazy-src="https://qiniu.codekylin.cn/img/20200418115059.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JVM堆内存"/></a><div class="content"><a class="title" href="/36436.html" title="JVM堆内存">JVM堆内存</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/44292.html" title="Java多线程详解"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-eorjzk.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Java多线程详解"/></a><div class="content"><a class="title" href="/44292.html" title="Java多线程详解">Java多线程详解</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/40200.html" title="谷粒商城记录"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="谷粒商城记录"/></a><div class="content"><a class="title" href="/40200.html" title="谷粒商城记录">谷粒商城记录</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/27082.html" title="Spring学习-3"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-4x28xo.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Spring学习-3"/></a><div class="content"><a class="title" href="/27082.html" title="Spring学习-3">Spring学习-3</a><time datetime="2022-07-12T11:47:29.799Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg')"><div id="footer-wrap"><div class="copyright">&copy;2019 - 2022 By Kylin</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/"><img class="icp-icon" src="https://img.alicdn.com/tfs/TB1..50QpXXXXX7XpXXXXXXXXXX-40-40.png"><span>湘ICP备2022005420号-1</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="font-plus" type="button" title="放大字体"><i class="fas fa-plus"></i></button><button id="font-minus" type="button" title="缩小字体"><i class="fas fa-minus"></i></button><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div></div><hr/><div id="local-search-results"></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"><script>function loadValine () {
  function initValine () {
    const valine = new Valine(Object.assign({
      el: '#vcomment',
      appId: 'ClIyIUhj1ue2rcRTsApYCR50-gzGzoHsz',
      appKey: 'ATug9IScYQBHILhKWEqBHYxM',
      placeholder: '昵称填入QQ号能获取到QQ头像哦~请输入正确的邮箱地址，你将会快速收到我的回复并且通过邮件通知你！~',
      avatar: 'robohash',
      meta: 'nick,mail,link'.split(','),
      pageSize: '10',
      lang: 'zh-cn',
      recordIP: false,
      serverURLs: 'https://cliyiuhj.lc-cn-n1-shared.com',
      emojiCDN: '',
      emojiMaps: "",
      enableQQ: true,
      path: window.location.pathname,
      requiredFields: ["nick,mail"],
      visitor: false
    }, null))
  }

  if (typeof Valine === 'function') initValine() 
  else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
}

if ('Valine' === 'Valine' || !true) {
  if (true) btf.loadComment(document.getElementById('vcomment'),loadValine)
  else setTimeout(loadValine, 0)
} else {
  function loadOtherComment () {
    loadValine()
  }
}</script></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script></div></body></html>